﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using SW.DDD.Domain;

namespace SW.DDD.Infrastructure
{
    /// <summary> 仓储 </summary>
    /// <typeparam name="TEntity">集合根</typeparam>
    /// <typeparam name="TKey">聚合根实体键</typeparam>
    public interface IRepository<TEntity, in TKey>
        where TKey : notnull
        where TEntity : class, IAggregateRoot<TKey>
    {
        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        TEntity Add(TEntity entity);

        /// <summary>
        /// 批量添加
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities);

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        TEntity Update(TEntity entity);

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity"></param>
        void Delete(TEntity entity);

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="entities"></param>
        void DeleteRange(IEnumerable<TEntity> entities);

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="whereExpression"></param>
        void DeleteRange(Expression<Func<TEntity, bool>> whereExpression);

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        /// <exception cref="EntityNotFoundException">当查找不到时</exception>
        async Task<TEntity> FindAsync(TKey id)
            => await FindOrNullAsync(id) ?? throw new EntityNotFoundException(typeof(TEntity), id);

        /// <summary>
        /// 查找的可空版本
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<TEntity?> FindOrNullAsync(TKey id);

        /// <summary>
        /// 根据条件查找
        /// </summary>
        /// <param name="findExpression"></param>
        /// <returns></returns>
        Task<TEntity?> FindByOrNullAsync(Expression<Func<TEntity, bool>> findExpression);

        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="TView">查询结果类型</typeparam>
        /// <param name="queryPlan"></param>
        /// <returns></returns>
        Task<IEnumerable<TView>> QueryAsync<TView>(Func<IQueryable<TEntity>, IQueryable<TView>> queryPlan);

        /// <summary>
        /// 计数
        /// </summary>
        /// <typeparam name="TView"></typeparam>
        /// <param name="queryPlan"></param>
        /// <returns></returns>
        Task<int> CountAsync<TView>(Func<IQueryable<TEntity>, IQueryable<TView>> queryPlan);

        /// <summary>
        /// 查找到实体后,删除实体并返回被删除的实体
        /// </summary>
        /// <param name="id"></param>
        /// <returns>移除的实体</returns>
        /// <exception cref="EntityNotFoundException">当查找不到时</exception>
        Task<TEntity> RemoveAsync(TKey id);
    }
}
